#include "IVFrame.h"
#include <wx/dcclient.h>
#include <wx/filedlg.h>
#include <wx/msgdlg.h>
#include <wx/file.h>

//(*InternalHeaders(IVFrame)
#include <wx/settings.h>
#include <wx/intl.h>
#include <wx/string.h>
//*)

//(*IdInit(IVFrame)
const long IVFrame::ID_IVSCROLLEDWINDOW = wxNewId();
const long IVFrame::ID_IVSTATUSBAR = wxNewId();
const long IVFrame::ID_IVFILEOPEN = wxNewId();
const long IVFrame::ID_IVFILECLOSE = wxNewId();
const long IVFrame::ID_IVFILESAVE = wxNewId();
const long IVFrame::ID_IVFRAMEEXIT = wxNewId();
const long IVFrame::ID_IVIMAGEENLARGE = wxNewId();
const long IVFrame::ID_IVIMAGESHRINK = wxNewId();
const long IVFrame::ID_IVIMAGEREVERSE = wxNewId();
const long IVFrame::ID_IVIMAGEGREYSCALE = wxNewId();
const long IVFrame::ID_IVIMAGEROTATECLOCKWISE = wxNewId();
const long IVFrame::ID_IVIMAGEROTATEUNCLOCKWISE = wxNewId();
const long IVFrame::iD_IVIMAGEROTATE = wxNewId();
//*)

BEGIN_EVENT_TABLE(IVFrame,wxFrame)
    //(*EventTable(IVFrame)
    //*)
    EVT_MENU(ID_IVFRAMEEXIT, IVFrame::OnIVFrameExit)
    EVT_MENU(ID_IVFILEOPEN, IVFrame::OnIVFileOpen)
    EVT_MENU(ID_IVFILECLOSE, IVFrame::OnIVFileClose)
    EVT_MENU(ID_IVFILESAVE, IVFrame::OnIVFileSave)
    EVT_MENU(ID_IVIMAGEENLARGE, IVFrame::OnIVImageEnlarge)
    EVT_MENU(ID_IVIMAGESHRINK, IVFrame::OnIVImageShrink)
END_EVENT_TABLE()

IVFrame::IVFrame(wxWindow* parent,wxWindowID id,const wxPoint& pos,const wxSize& size)
{
    //(*Initialize(IVFrame)
    wxMenuItem* IVFrameExit;
    wxMenuItem* IVImageRotateClockwise;
    wxMenuItem* IVFileClose;
    wxMenuItem* IVFileOpen;
    wxMenu* IVFileMenu;
    wxMenuItem* IVFileSave;
    wxMenuItem* IVImageReverse;
    wxMenuItem* IVImageGreyscale;
    wxMenuItem* IVImageRotateUnclockwise;
    wxMenu* IVImageRotate;

    Create(parent, id, _("Image view framework"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, _T("id"));
    SetClientSize(wxDefaultSize);
    Move(wxDefaultPosition);
    IVScrolledWindow = new wxScrolledWindow(this, ID_IVSCROLLEDWINDOW, wxPoint(144,352), wxDefaultSize, wxHSCROLL|wxVSCROLL, _T("ID_IVSCROLLEDWINDOW"));
    IVScrolledWindow->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_ACTIVEBORDER));
    IVStatusBar = new wxStatusBar(this, ID_IVSTATUSBAR, 0, _T("ID_IVSTATUSBAR"));
    int __wxStatusBarWidths_1[1] = { -10 };
    int __wxStatusBarStyles_1[1] = { wxSB_NORMAL };
    IVStatusBar->SetFieldsCount(1,__wxStatusBarWidths_1);
    IVStatusBar->SetStatusStyles(1,__wxStatusBarStyles_1);
    SetStatusBar(IVStatusBar);
    IVMenuBar = new wxMenuBar();
    IVFileMenu = new wxMenu();
    IVFileOpen = new wxMenuItem(IVFileMenu, ID_IVFILEOPEN, _("&Open\tCtrl-O"), _("Open image file."), wxITEM_NORMAL);
    IVFileMenu->Append(IVFileOpen);
    IVFileClose = new wxMenuItem(IVFileMenu, ID_IVFILECLOSE, _("&Close\tCtrl-C"), _("Close image file."), wxITEM_NORMAL);
    IVFileMenu->Append(IVFileClose);
    IVFileSave = new wxMenuItem(IVFileMenu, ID_IVFILESAVE, _("&Save as\tCtrl-S"), _("Save the current iamge."), wxITEM_NORMAL);
    IVFileMenu->Append(IVFileSave);
    IVFileMenu->AppendSeparator();
    IVFrameExit = new wxMenuItem(IVFileMenu, ID_IVFRAMEEXIT, _("E&xit\tCtrl-X"), _("Exit the programme."), wxITEM_NORMAL);
    IVFileMenu->Append(IVFrameExit);
    IVMenuBar->Append(IVFileMenu, _("&File"));
    IVOperateMenu = new wxMenu();
    IVImageEnlarge = new wxMenuItem(IVOperateMenu, ID_IVIMAGEENLARGE, _("&Enlarge\tCtrl-E"), _("Enlarge the image."), wxITEM_NORMAL);
    IVOperateMenu->Append(IVImageEnlarge);
    IVImageShrink = new wxMenuItem(IVOperateMenu, ID_IVIMAGESHRINK, _("S&hrink\tCtrl-H"), _("Shrink the image."), wxITEM_NORMAL);
    IVOperateMenu->Append(IVImageShrink);
    IVOperateMenu->AppendSeparator();
    IVImageReverse = new wxMenuItem(IVOperateMenu, ID_IVIMAGEREVERSE, _("Reverse"), _("Reverse the image."), wxITEM_NORMAL);
    IVOperateMenu->Append(IVImageReverse);
    IVImageGreyscale = new wxMenuItem(IVOperateMenu, ID_IVIMAGEGREYSCALE, _("Greyscale"), _("Change the image to grey image."), wxITEM_NORMAL);
    IVOperateMenu->Append(IVImageGreyscale);
    IVImageRotate = new wxMenu();
    IVImageRotateClockwise = new wxMenuItem(IVImageRotate, ID_IVIMAGEROTATECLOCKWISE, _("Clockwise"), _("Rotate the image clockwise"), wxITEM_NORMAL);
    IVImageRotate->Append(IVImageRotateClockwise);
    IVImageRotateUnclockwise = new wxMenuItem(IVImageRotate, ID_IVIMAGEROTATEUNCLOCKWISE, _("Unclockwise"), _("Rotate the image unclockwise."), wxITEM_NORMAL);
    IVImageRotate->Append(IVImageRotateUnclockwise);
    IVOperateMenu->Append(iD_IVIMAGEROTATE, _("Rotate"), IVImageRotate, _("Rotate the image."));
    IVMenuBar->Append(IVOperateMenu, _("O&perate"));
    SetMenuBar(IVMenuBar);
    Center();

    IVScrolledWindow->Connect(ID_IVSCROLLEDWINDOW,wxEVT_PAINT,(wxObjectEventFunction)&IVFrame::OnIVScrolledWindowPaint,0,this);
    Connect(ID_IVIMAGEREVERSE,wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&IVFrame::OnIVImageReverseSelected);
    Connect(ID_IVIMAGEGREYSCALE,wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&IVFrame::OnIVImageGreyscaleSelected);
    Connect(ID_IVIMAGEROTATECLOCKWISE,wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&IVFrame::OnIVImageRotateClockwiseSelected);
    Connect(ID_IVIMAGEROTATEUNCLOCKWISE,wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&IVFrame::OnIVImageRotateUnclockwiseSelected);
    //*)

    // do some init issues
    IVFrameInit();
}

IVFrame::~IVFrame()
{
    //(*Destroy(IVFrame)
    //*)

    // Free the memory of image if exsit
    if (IVImage != NULL)
    {
        delete IVImage;
        IVImage = NULL;
        delete IVImageBK;
        IVImageBK = NULL;
    }
}

void IVFrame::IVFrameInit(void)
{
    IVImage = NULL;
    IVImageBK = NULL;
    IVScaleCoefficient = 1.0;

    IVSetOperateValid(false);
}

void IVFrame::OnIVScrolledWindowPaint(wxPaintEvent& event)
{
    wxPaintDC dc(IVScrolledWindow);
    IVScrolledWindow->DoPrepareDC(dc);

    if (IVImage == NULL)
    {
        dc.Clear();
    }
    else
    {
        wxBitmap bitmap(*IVImage);
        wxCoord x = 0, y = 0;
        IVScrolledWindow->SetScrollRate(10, 10);
        IVScrolledWindow->SetVirtualSize(IVImage->GetWidth(), IVImage->GetHeight());
        dc.DrawBitmap(bitmap, x, y, true);
    }
}

void IVFrame::OnIVFrameExit(wxCommandEvent &event)
{
    Close();
}

void IVFrame::IVReloadImage(wxString fileName)
{
    if (IVImage != NULL)
    {
        delete IVImage;
        IVImage = NULL;
        delete IVImageBK;
        IVImageBK = NULL;

        IVScaleCoefficient = 1.0;
        IVSetOperateValid(false);
    }
    if (fileName != wxEmptyString)
    {
        IVImage = new wxImage(fileName);
        IVImageBK = new wxImage(fileName);

        IVSetOperateValid(true);
    }
}

void IVFrame::OnIVFileOpen(wxCommandEvent &event)
{
    wxFileDialog *fileDialog =
            new wxFileDialog(this, wxT("Choose a file"), wxT(""), wxEmptyString,
            wxT("Image files.|*.bmp;*.png;*.jpg;*.jpeg;*.ico"),
            wxOPEN);
    if (fileDialog->ShowModal() == wxID_OK)
    {
        IVReloadImage(fileDialog->GetPath());
        IVScrolledWindow->Refresh();
    }
}

void IVFrame::OnIVFileSave(wxCommandEvent &event)
{
    wxFileDialog *fileDialog =
            new wxFileDialog(this, wxT("Choose a file"), wxT(""), wxEmptyString,
            wxT("JPEG File.|*.jpg;*.jpeg|PNG file.|*.png"),
            wxFD_SAVE);
    if (fileDialog->ShowModal() == wxID_OK)
    {
        if (wxFile::Exists(fileDialog->GetPath()) == true)
        {
            wxMessageDialog dialog(NULL, wxT("The file is existed, overwrite ?"),
                wxT("Warning"), wxYES_NO | wxICON_QUESTION | wxNO_DEFAULT);
            switch (dialog.ShowModal())
            {
                case wxID_NO:
                    return;
                default:
                    break;
            }
        }
        if (IVImage->SaveFile(fileDialog->GetPath()))
        {
            wxMessageBox(wxT("The image saved sucessfully!"), wxT("Message"), wxOK);
        }
    }
}

void IVFrame::OnIVFileClose(wxCommandEvent &event)
{
    IVReloadImage(wxEmptyString);
    IVScrolledWindow->Refresh();
    IVScrolledWindow->SetVirtualSize(10, 10);
}

void IVFrame::OnIVImageShrink(wxCommandEvent &event)
{
    IVScaleCoefficient /= 1.1;
    if (IVScaleCoefficient < 0.1)
    {
        IVScaleCoefficient *= 1.1;
        return;
    }
    delete IVImage;
    IVImage = new wxImage(*IVImageBK);
    IVImage->Rescale((int)(IVImageBK->GetWidth() * IVScaleCoefficient),
        (int)(IVImageBK->GetHeight() * IVScaleCoefficient));
    IVScrolledWindow->Refresh();
}

void IVFrame::OnIVImageEnlarge(wxCommandEvent &event)
{
    IVScaleCoefficient *= 1.1;
    if (IVScaleCoefficient > 10)
    {
        IVScaleCoefficient /= 1.1;
        return;
    }
    delete IVImage;
    IVImage = new wxImage(*IVImageBK);
    IVImage->Rescale((int)(IVImageBK->GetWidth() * IVScaleCoefficient),
        (int)(IVImageBK->GetHeight() * IVScaleCoefficient));
    IVScrolledWindow->Refresh();
}

void IVFrame::IVSetOperateValid(bool flag)
{
    IVMenuBar->FindItem(ID_IVIMAGEENLARGE)->Enable(flag);
    IVMenuBar->FindItem(ID_IVIMAGESHRINK)->Enable(flag);
    IVMenuBar->FindItem(ID_IVFILESAVE)->Enable(flag);
    IVMenuBar->FindItem(ID_IVFILECLOSE)->Enable(flag);
    IVMenuBar->FindItem(ID_IVIMAGEREVERSE)->Enable(flag);
    IVMenuBar->FindItem(ID_IVIMAGEGREYSCALE)->Enable(flag);
    IVMenuBar->FindItem(iD_IVIMAGEROTATE)->Enable(flag);
}

void IVFrame::OnIVImageReverseSelected(wxCommandEvent& event)
{
    unsigned char *imageData = IVImage->GetData();
    int begin = 0;
    int end = IVImage->GetWidth() * IVImage->GetHeight() * 3;
    while (begin < end)
    {
        *imageData = 255 - *imageData;
        imageData++;
        begin++;
    }
    IVScrolledWindow->Refresh();

    // change the backup image to reverse
    imageData = IVImageBK->GetData();
    begin = 0;
    end = IVImageBK->GetWidth() * IVImageBK->GetHeight() * 3;
    while (begin < end)
    {
        *imageData = 255 - *imageData;
        imageData++;
        begin++;
    }
}

void IVFrame::OnIVImageGreyscaleSelected(wxCommandEvent& event)
{
    wxImage imageTmp = IVImage->ConvertToGreyscale();
    wxImage imageTmpBK = IVImageBK->ConvertToGreyscale();
    delete IVImage;
    IVImage = new wxImage(imageTmp);
    delete IVImageBK;
    IVImageBK = new wxImage(imageTmpBK);
    IVScrolledWindow->Refresh();
}

void IVFrame::OnIVImageRotateClockwiseSelected(wxCommandEvent& event)
{
    wxImage imageTmp = IVImage->Rotate90(true);
    wxImage imageTmpBK = IVImageBK->Rotate90(true);
    delete IVImage;
    IVImage = new wxImage(imageTmp);
    delete IVImageBK;
    IVImageBK = new wxImage(imageTmpBK);
    IVScrolledWindow->Refresh();
}

void IVFrame::OnIVImageRotateUnclockwiseSelected(wxCommandEvent& event)
{
    wxImage imageTmp = IVImage->Rotate90(false);
    wxImage imageTmpBK = IVImageBK->Rotate90(false);
    delete IVImage;
    IVImage = new wxImage(imageTmp);
    delete IVImageBK;
    IVImageBK = new wxImage(imageTmpBK);
    IVScrolledWindow->Refresh();
}
